/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package compression;

import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author danang
 */
public class Kompresi {

    static int head = 0;

    public static ArrayList tovbyte(int s) {

        //convert integer menjadi arraylist v-byte
        ArrayList<Byte> L = new ArrayList<Byte>();
        while (s >= 128) {
            L.add((byte) (s & 0x7F));
            s >>>= 7;
        }
        L.add(((byte) (s | 0x80)));
        return L;
    }

    public static String Encode(ArrayList<Integer> L) {
        // meng-encode satu baris integer
        //delta encode
        ArrayList<Integer> Delta = new ArrayList<Integer>();
        int sem = 0;
        //System.out.println("\nhasil encode delta : ");
        for (int i = 0; i < L.size(); i++) {
            if (i == 0) {

                Delta.add(L.get(0) - head);
                head = L.get(0);
                //System.out.print((L.get(0)-head)+",");
            } else if (i == 1) {
                sem = L.get(1);
                Delta.add(sem);
                //System.out.print(sem+",");
            } else {
                sem = L.get(i) - L.get(i - 1);
                Delta.add(sem);
                //System.out.print(sem+",");
            }
        }


        //v-byte encode
        ArrayList<Byte> Enc = new ArrayList<Byte>();
        int j = 0;
        for (int s : Delta) {
            while (s >= 128) {
                Enc.add((byte) (s & 0x7F));
                s >>>= 7;
            }
            Enc.add(((byte) (s | 0x80)));

        }
        StringBuilder sb = new StringBuilder();
        String s;
        for (int i : Enc) {
            s = Integer.toHexString(i);
            if (s.length()>=2) {
                sb.append(s.substring(s.length() - 2, s.length()));
            } else {
                sb.append("0"+s);
            }
        }

        return sb.toString();

    }

    public static String EncodeGabung(ArrayList<ArrayList<Integer>> A) {
        //menggabungkan hasil encode tiap baris 
        String sem;
        i = 0;
        StringBuilder SB = new StringBuilder();
        head = 0;
        do {
            sem = Encode(A.get(i));
            SB.append(sem);
            if ((i + 1) < A.size()) {
                SB.append("\n");
            }
            i++;
        } while (i < A.size());
        //System.out.println("Hasil encode\n" + SB.toString());
        return SB.toString();
    }

    public static ArrayList<ArrayList<Integer>> DecodeGabung(String a) {
        //menggabungkan hasil decode dari setiap baris
        ArrayList<ArrayList<Integer>> A = new ArrayList<ArrayList<Integer>>();
        //parse string a menjadi arraylist of string
        //ArrayList<String> S = new ArrayList<String>();
        int k = 0;
        int j = 0;
        /*String sem = "";
        while (j < a.length()) {
            if (a.charAt(j) != '\n') {
                sem += a.substring(j, j + 1);
            } else {
                S.add(sem);
                sem = "";
            }
            j++;
        }
        S.add(sem);*/
        String[] S = a.split("\n");
        i = 0;
        ArrayList<Integer> L = null;
        head = 0;
        //System.out.println("Hasil decode");
        while (i < S.length) {
            L = new ArrayList<Integer>();
            L = Decode(S[i]);

            //for (int r : L) {
            //   System.out.print(r + ",");
            //}
            //System.out.println("");
            A.add(L);
            i++;
        }
        return A;
    }

    public static ArrayList Decode(String a) {
        //men-decode satu baris 

        //parsing 2-gram
        ArrayList<Byte> L2 = new ArrayList<Byte>();
        //mengisi arraylist L2 dengan 2-gram byte
        Byte b;
        String f;
        for (int i = 0; i < a.length(); i += 2) {
            f = a.substring(i, i + 2);
            b = (byte) Integer.parseInt(f, 16);
            L2.add(b);
        }


        ArrayList<Integer> L3 = new ArrayList<Integer>();

        // v-byte decode
        //memasukkan integer hasil decode ke L3
        for (int i = 0; i < L2.size(); i++) {
            int s = L2.get(i);
            int position = 0;
            int result = ((int) s & 0x7F);
            while (((s & 0x80) == 0) && ((i + 1) < L2.size())) {
                i++;
                s = L2.get(i);
                position += 1;
                int unsignedByte = ((int) s & 0x7F);
                result |= (unsignedByte << (7 * position));

            }

            L3.add(result);
        }

        //delta decode
        ArrayList<Integer> L4 = new ArrayList<Integer>();
        int sem = 0;

        for (int i = 0; i < L3.size(); i++) {
            if (i == 0) {
                head = L3.get(0) + head;
                L4.add(head);
            } else if (i == 1) {
                sem = L3.get(i);
                L4.add(sem);
            } else {
                sem = L3.get(i) + sem;
                L4.add(sem);
            }

        }
        return L4;
    }
    static int i = 0;
    
    /*public static void main(String[] args) {
        ArrayList<ArrayList<Integer>> A = DecodeGabung("8b3089\n"
                + "894488\n"
                + "872b8d\n"
                + "cd368f\n"
                + "39814388\n"
                + "54830c9c\n"
                + "8957ad\n"
                + "18815a8d\n"
                + "30814b88\n"
                + "993e8f\n"
                + "10813789\n"
                + "2a81328d\n"
                + "1c81308f\n"
                + "fb3c88\n"
                + "70846798");
        for (List a : A) {
            for (int j : (ArrayList<Integer>) a) {
                System.out.print(j+",");
            }
            System.out.println();
        }
    }*/
    
}
